using System;
using SharpMud.Net.Telnet.IAC;

namespace SharpMud.Net.Telnet.Session.NegotationAgents
{
	/// <summary>
	/// This is the negotiation daemon for remote localecho.
	/// Basically inverting the principal of the server volunteering to echo the client.
	/// </summary>
	public class RemoteEcho : IFeatureNegotiationAgent
	{
		private TelnetSessionBase			_HostSession;
		private FeatureNegotiationBehavior	_Behavior;
		private bool						_IsNegotiationRefused;

		#region Constructors
		private RemoteEcho()
		{
		}
		public RemoteEcho(TelnetSessionBase hostSession)
		{
			_Behavior = (FeatureNegotiationBehavior)(-1);

			_Enabled = true;
			_ChangesPending = 0;
			_HostSession = hostSession;
			_RequireClientVerification = false;
			hostSession.IAC.In.IAC_Feature_Negotiation +=new SharpMud.Net.Telnet.Session.DataProcessors.IAC.IACInputEventHandler(IAC_Feature_Negotiation);
		}

		private bool _Enabled;

		private int _ChangesPending;
		public bool ChangePending
		{
			get
			{
				return (_ChangesPending>0);
			}
		}

		private bool _RequireClientVerification;
		#endregion

		private void IAC_Feature_Negotiation(SharpMud.Net.Telnet.Session.DataProcessors.IAC.InputLayer sender, SharpMud.Net.Telnet.Session.DataProcessors.IAC.IACInputEventArgs e)
		{
			if(e.FeatureType!=ControlCodes.ECHO) return;
			
			if(e.NegotiationQuery == ControlCodes.WILL)
			{
				//The client is saying it wants to ECHO *us*
				//Not expected to get this message, but tell it NOT TOO anyway
				_HostSession.IAC.Out.Send_FeatureNegotiation_Packet(ControlCodes.DONT,ControlCodes.ECHO);
				return;
			}
			if(e.NegotiationQuery == ControlCodes.WONT)
			{
				//The client is saying it WILL NOT echo *us*
				//Which is good, because it shouldnt
				return;
			}
			if(e.NegotiationQuery == ControlCodes.DO)
			{
				if(_Enabled)
					_Enabled = false;
				if(ChangePending)
					_ChangesPending--;
				return;
			}
			if(e.NegotiationQuery == ControlCodes.DONT)
			{
				if(!_Enabled)
					_Enabled = true;
				if(ChangePending)
					_ChangesPending--;
				return;
			}
		}
		#region IFeatureNegotiationAgent Members

		public SharpMud.Net.Telnet.Session.FeatureNegotiationBehavior Behavior
		{
			get
			{
				return _Behavior;
			}
			set
			{
				if(value!=_Behavior)
				{
					if(value==FeatureNegotiationBehavior.DemandClientSupport && this.Status!=TriState.True)
					{
						this.TurnFeatureOn();
					}
					if(value==FeatureNegotiationBehavior.RejectClientOnDemand && this.Status!=TriState.False)
					{
						this.TurnFeatureOff();
					}
					if(value==FeatureNegotiationBehavior.AcceptClientOnDemand && this.Status!=TriState.False)
					{
						this.TurnFeatureOn();
					}
					_Behavior = value;
				}
			}
		}

		public System.TriState Status
		{
			get
			{
				if(_IsNegotiationRefused)
					return TriState.False;
				if(this._RequireClientVerification && this._ChangesPending>0)
					return TriState.UseDefault;
				if(this._Enabled)
					return TriState.True;
				else
					return TriState.False;
			}
		}

		public bool EffectiveStatus
		{
			get
			{
				return this._Enabled;
			}
		}

		/// <summary>
		/// Tell the client that the server will not echo user input. This means the client
		/// should echo user input. For some reason, Windows Telnet does not. But alas, I digress.
		/// </summary>
		public void TurnFeatureOn()
		{
			if(_Enabled==false && (ChangePending==false || _RequireClientVerification==false))
			{
				//Need to turn remote echoing back on
				//(Tell client that we aren't echong anything anymore. Hehehehe)
				_ChangesPending++;
				this._HostSession.IAC.Out.Send_FeatureNegotiation_Packet(ControlCodes.WONT,ControlCodes.ECHO);
				if(!_RequireClientVerification)
				{
					_Enabled = true;
				}
				return;
			}
		}

		/// <summary>
		/// Tell the client that the server will echo user input. Its not honest, but the client
		/// will then not echo the user.
		/// </summary>
		public void TurnFeatureOff()
		{
			if(_Enabled==true && (ChangePending==false || _RequireClientVerification==false))
			{
				//Need to turn remote echoing off
				//(Tell client that echoing will be done server side. Hahahaha)
				_ChangesPending++;
				this._HostSession.IAC.Out.Send_FeatureNegotiation_Packet(ControlCodes.WILL,ControlCodes.ECHO);
				if(!_RequireClientVerification)
				{
					_Enabled = false;
				}
				return;
			}
		}

		#endregion
	}
}